"""
股票数据API路由
"""
import logging
from datetime import datetime, timedelta
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, Path
from sqlalchemy.orm import Session
from sqlalchemy import func, desc
from pydantic import BaseModel, Field

from modules.models.base import get_db
from modules.models.stock import SecurityInfo, DailyQuote, TechnicalIndicator
from modules.tasks.stock_tasks import collect_stock_data, calculate_stock_indicators
from modules.api.auth import get_current_active_user, User

# 配置日志
logger = logging.getLogger("api.stocks")

# 创建路由
router = APIRouter()


# 模型定义
class StockBase(BaseModel):
    """股票基础信息模型"""
    code: str
    name: str
    exchange: str
    is_active: int
    
    class Config:
        orm_mode = True


class QuoteBase(BaseModel):
    """股票行情基础数据模型"""
    trade_date: datetime
    open: Optional[float] = None
    high: Optional[float] = None
    low: Optional[float] = None
    close: Optional[float] = None
    volume: Optional[float] = None
    amount: Optional[float] = None
    turnover: Optional[float] = None
    
    class Config:
        orm_mode = True


class QuoteWithIndicators(QuoteBase):
    """包含技术指标的行情数据模型"""
    ma5: Optional[float] = None
    ma10: Optional[float] = None
    ma20: Optional[float] = None
    rsi6: Optional[float] = None
    rsi12: Optional[float] = None
    macd: Optional[float] = None
    macd_signal: Optional[float] = None
    macd_hist: Optional[float] = None
    boll_upper: Optional[float] = None
    boll_middle: Optional[float] = None
    boll_lower: Optional[float] = None
    
    class Config:
        orm_mode = True


class TaskResponse(BaseModel):
    """任务响应模型"""
    task_id: str
    message: str


# API路由
@router.get("/list", response_model=List[StockBase], summary="获取股票列表")
async def get_stock_list(
    exchange: Optional[str] = Query(None, description="交易所: SSE/SZSE"),
    is_active: Optional[int] = Query(1, description="是否活跃: 0/1"),
    limit: int = Query(100, description="返回结果限制数量", ge=1, le=1000),
    offset: int = Query(0, description="结果偏移量", ge=0),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    """
    获取股票列表
    
    - **exchange**: 交易所，可选，如SSE（上交所）或SZSE（深交所）
    - **is_active**: 是否活跃，默认为1（活跃）
    - **limit**: 返回结果数量限制，默认100，最大1000
    - **offset**: 结果偏移量，默认0
    """
    try:
        query = db.query(SecurityInfo).filter(SecurityInfo.type == 'stock')
        
        if exchange:
            query = query.filter(SecurityInfo.exchange == exchange)
        
        if is_active is not None:
            query = query.filter(SecurityInfo.is_active == is_active)
        
        total = query.count()
        stocks = query.order_by(SecurityInfo.code).offset(offset).limit(limit).all()
        
        return stocks
    
    except Exception as e:
        logger.error(f"获取股票列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取股票列表失败: {str(e)}")


@router.get("/{code}", response_model=StockBase, summary="获取单只股票信息")
async def get_stock_info(
    code: str = Path(..., description="股票代码"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    """
    获取单只股票信息
    
    - **code**: 股票代码
    """
    try:
        stock = db.query(SecurityInfo).filter(
            SecurityInfo.code == code,
            SecurityInfo.type == 'stock'
        ).first()
        
        if not stock:
            raise HTTPException(status_code=404, detail=f"股票代码 {code} 不存在")
        
        return stock
    
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取股票 {code} 信息失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取股票信息失败: {str(e)}")


@router.get("/{code}/quotes", response_model=List[QuoteBase], summary="获取股票行情数据")
async def get_stock_quotes(
    code: str = Path(..., description="股票代码"),
    start_date: Optional[str] = Query(None, description="开始日期，格式：YYYY-MM-DD"),
    end_date: Optional[str] = Query(None, description="结束日期，格式：YYYY-MM-DD"),
    limit: int = Query(30, description="返回结果限制数量", ge=1, le=1000),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    """
    获取股票行情数据
    
    - **code**: 股票代码
    - **start_date**: 开始日期，格式：YYYY-MM-DD
    - **end_date**: 结束日期，格式：YYYY-MM-DD
    - **limit**: 返回结果数量限制，默认30天，最大1000天
    """
    try:
        # 获取股票ID
        stock = db.query(SecurityInfo).filter(
            SecurityInfo.code == code,
            SecurityInfo.type == 'stock'
        ).first()
        
        if not stock:
            raise HTTPException(status_code=404, detail=f"股票代码 {code} 不存在")
        
        # 构建查询
        query = db.query(DailyQuote).filter(DailyQuote.security_id == stock.id)
        
        # 处理日期范围
        if start_date:
            query = query.filter(DailyQuote.trade_date >= datetime.strptime(start_date, "%Y-%m-%d").date())
        
        if end_date:
            query = query.filter(DailyQuote.trade_date <= datetime.strptime(end_date, "%Y-%m-%d").date())
        
        # 获取结果，按日期降序排列
        quotes = query.order_by(desc(DailyQuote.trade_date)).limit(limit).all()
        
        return quotes
    
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"日期格式错误: {str(e)}")
    except Exception as e:
        logger.error(f"获取股票 {code} 行情数据失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取股票行情数据失败: {str(e)}")


@router.get("/{code}/indicators", response_model=List[QuoteWithIndicators], summary="获取股票行情及技术指标")
async def get_stock_indicators(
    code: str = Path(..., description="股票代码"),
    start_date: Optional[str] = Query(None, description="开始日期，格式：YYYY-MM-DD"),
    end_date: Optional[str] = Query(None, description="结束日期，格式：YYYY-MM-DD"),
    limit: int = Query(30, description="返回结果限制数量", ge=1, le=1000),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    """
    获取股票行情数据及技术指标
    
    - **code**: 股票代码
    - **start_date**: 开始日期，格式：YYYY-MM-DD
    - **end_date**: 结束日期，格式：YYYY-MM-DD
    - **limit**: 返回结果数量限制，默认30天，最大1000天
    """
    try:
        # 获取股票ID
        stock = db.query(SecurityInfo).filter(
            SecurityInfo.code == code,
            SecurityInfo.type == 'stock'
        ).first()
        
        if not stock:
            raise HTTPException(status_code=404, detail=f"股票代码 {code} 不存在")
        
        # 构建查询
        query = db.query(
            DailyQuote.trade_date,
            DailyQuote.open,
            DailyQuote.high,
            DailyQuote.low,
            DailyQuote.close,
            DailyQuote.volume,
            DailyQuote.amount,
            DailyQuote.turnover,
            TechnicalIndicator.ma5,
            TechnicalIndicator.ma10,
            TechnicalIndicator.ma20,
            TechnicalIndicator.rsi6,
            TechnicalIndicator.rsi12,
            TechnicalIndicator.macd,
            TechnicalIndicator.macd_signal,
            TechnicalIndicator.macd_hist,
            TechnicalIndicator.boll_upper,
            TechnicalIndicator.boll_middle,
            TechnicalIndicator.boll_lower
        ).join(
            TechnicalIndicator,
            DailyQuote.id == TechnicalIndicator.daily_quote_id,
            isouter=True
        ).filter(
            DailyQuote.security_id == stock.id
        )
        
        # 处理日期范围
        if start_date:
            query = query.filter(DailyQuote.trade_date >= datetime.strptime(start_date, "%Y-%m-%d").date())
        
        if end_date:
            query = query.filter(DailyQuote.trade_date <= datetime.strptime(end_date, "%Y-%m-%d").date())
        
        # 获取结果，按日期降序排列
        results = query.order_by(desc(DailyQuote.trade_date)).limit(limit).all()
        
        # 构建返回结果
        quotes_with_indicators = []
        for row in results:
            quote = QuoteWithIndicators(
                trade_date=row.trade_date,
                open=row.open,
                high=row.high,
                low=row.low,
                close=row.close,
                volume=row.volume,
                amount=row.amount,
                turnover=row.turnover,
                ma5=row.ma5,
                ma10=row.ma10,
                ma20=row.ma20,
                rsi6=row.rsi6,
                rsi12=row.rsi12,
                macd=row.macd,
                macd_signal=row.macd_signal,
                macd_hist=row.macd_hist,
                boll_upper=row.boll_upper,
                boll_middle=row.boll_middle,
                boll_lower=row.boll_lower
            )
            quotes_with_indicators.append(quote)
        
        return quotes_with_indicators
    
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"日期格式错误: {str(e)}")
    except Exception as e:
        logger.error(f"获取股票 {code} 行情及技术指标失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取股票行情及技术指标失败: {str(e)}")


@router.post("/{code}/collect", response_model=TaskResponse, summary="手动触发股票数据采集")
async def trigger_stock_data_collection(
    code: str = Path(..., description="股票代码"),
    days: int = Query(30, description="采集天数", ge=1, le=365),
    current_user: User = Depends(get_current_active_user)
):
    """
    手动触发股票数据采集任务
    
    - **code**: 股票代码
    - **days**: 采集天数，默认30天，最大365天
    """
    try:
        # 计算日期范围
        end_date = datetime.now().strftime('%Y%m%d')
        start_date = (datetime.now() - timedelta(days=days)).strftime('%Y%m%d')
        
        # 触发采集任务
        task = collect_stock_data.delay(code, start_date, end_date)
        
        return {
            "task_id": task.id,
            "message": f"股票 {code} 数据采集任务已提交，采集范围: {start_date} 至 {end_date}"
        }
    
    except Exception as e:
        logger.error(f"触发股票 {code} 数据采集任务失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"触发数据采集任务失败: {str(e)}")


@router.post("/{code}/calculate_indicators", response_model=TaskResponse, summary="手动触发技术指标计算")
async def trigger_indicators_calculation(
    code: str = Path(..., description="股票代码"),
    recalculate: bool = Query(False, description="是否重新计算所有指标"),
    current_user: User = Depends(get_current_active_user)
):
    """
    手动触发股票技术指标计算任务
    
    - **code**: 股票代码
    - **recalculate**: 是否重新计算所有指标，默认为False（仅计算新数据）
    """
    try:
        # 触发计算任务
        task = calculate_stock_indicators.delay(code, recalculate)
        
        return {
            "task_id": task.id,
            "message": f"股票 {code} 技术指标计算任务已提交，重新计算所有: {recalculate}"
        }
    
    except Exception as e:
        logger.error(f"触发股票 {code} 技术指标计算任务失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"触发技术指标计算任务失败: {str(e)}")